#include "door_common.h"
#include "gkt_io_debounce.h"

#if defined(GKT_CONFIG_DOOR_TAMPER_ENABLE) && GKT_CONFIG_DOOR_TAMPER_ENABLE	\
	&& defined(GKT_CONFIG_DOOR_TAMPER_WKIO_PIN) \
	&& !defined(GKT_CONFIG_DOOR_TAMPER_GPIO_PIN)

#define DOOR_TAMPER_WKIO_GPIO_PIN	\
	GKT_GPIO_PIN(0, 0, GKT_CONFIG_DOOR_TAMPER_WKIO_PIN)

#ifndef GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL
static __RETMEM_USR uint32_t s_door_tamper_detect_level;
#endif

typedef struct _door_tamper {
	uint32_t	io_debounce_state;
} door_tamper_s;
static door_tamper_s s_door_tamper;

int gkt_door_tamper_is_detected(void)
{
	uint32_t level;
	int retval;

	retval = gkt_gpio_get_pin_level(DOOR_TAMPER_WKIO_GPIO_PIN, 
				&level);
	return ((GKT_SUCCESS == retval) 
			&& (DOOR_TAMPER_DETECT_LEVEL == level)) ? 1 : 0;
}

void gkt_door_tamper_stop(void)
{
	s_door_tamper.io_debounce_state &= ~DOOR_TAMPER_IO_DEBOUNCE_BUSY;
	door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, 0);
}

static void door_tamper_debounce_complete(int result, int detect)
{
	gkt_trace("door_tamper_debounce_complete: state(0x%x), result(%d)\n", 
			s_door_tamper.io_debounce_state, result);

	if (s_door_tamper.io_debounce_state  & DOOR_TAMPER_IO_DEBOUNCE_BUSY) {
		s_door_tamper.io_debounce_state &= ~DOOR_TAMPER_IO_DEBOUNCE_BUSY;
		if (GKT_IO_DEBOUNCE_OK == result)
			door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, detect);
	}
}

static void door_tamper_detect_notify(void)
{
	int retval;

	gkt_trace("door_tamper_detect: state(0x%x)\n", s_door_tamper.io_debounce_state);

	if (s_door_tamper.io_debounce_state & DOOR_TAMPER_IO_DEBOUNCE_READY) {
		if (s_door_tamper.io_debounce_state & DOOR_TAMPER_IO_DEBOUNCE_BUSY)
			return;

		retval = gkt_io_debounce_start(GKT_IO_DEBOUNCE_ID(door_tamper), 1, 0);
		if (GKT_SUCCESS == retval) {
			s_door_tamper.io_debounce_state |= DOOR_TAMPER_IO_DEBOUNCE_BUSY;
			return;
		}
	}

	door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, 1);
}

int door_tamper_init(void)
{
	gkt_wkio_attr_s attr;
	gkt_io_debounce_attr_s io_debounce_attr;
	uint32_t detect_check_times;
	int detect, wakedup, retval;

	io_debounce_attr.step_ms = 0;
	io_debounce_attr.detect_fn = gkt_door_tamper_is_detected;
	io_debounce_attr.complete_fn = door_tamper_debounce_complete;
	retval = gkt_io_debounce_config(GKT_IO_DEBOUNCE_ID(door_tamper),
				&io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_tamper.io_debounce_state = DOOR_TAMPER_IO_DEBOUNCE_READY;
	else
		gkt_error("door_tamper: debounce config failed!\n");

	retval = gkt_gpio_config(DOOR_TAMPER_WKIO_GPIO_PIN,
						GKT_GPIO_F_INPUT, NULL);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper_init: <0> config gpio failed %d\n", retval);
		return retval;
	}
#ifndef GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL
	if (GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode) {
		gkt_gpio_get_pin_level(DOOR_TAMPER_WKIO_GPIO_PIN, 
				&s_door_tamper_detect_level);
		s_door_tamper_detect_level ^= 1;
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);
	}
#endif

	attr.polarity = (0 == DOOR_TAMPER_DETECT_LEVEL) ?
		GKT_WKIO_POL_FALL_EDGE : GKT_WKIO_POL_RAISE_EDGE;
	attr.check = gkt_door_tamper_is_detected;
	attr.notify = door_tamper_detect_notify;
	retval = gkt_wkio_set(GKT_CONFIG_DOOR_TAMPER_WKIO_PIN, &attr);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper: wkio set failed %d\n", retval);
		return retval;
	}

	if (GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode) {
		wakedup = gkt_wkio_is_wakeup(GKT_CONFIG_DOOR_TAMPER_WKIO_PIN);
		if (!wakedup)
			goto done;

		detect_check_times = DOOR_TAMPER_WAKEUP_CHECK_TIMES;
		do {
			detect = gkt_door_tamper_is_detected();
			if (!detect)
				goto done;
			gkt_delay_us(DOOR_TAMPER_WAKEUP_CHECK_UNIT_US);
		} while (--detect_check_times > 0);

		gkt_info("door_tamper_init: *** WAKEUP ***\n");
		gkt_wakeup_set_source(GKT_WAKEUP_SRC_door_tamper);
	}	

done:
	return GKT_SUCCESS;
}

int gkt_door_tamper_init(void)
{
	gkt_wkio_attr_s attr;
	gkt_io_debounce_attr_s io_debounce_attr;
	int retval;

	gkt_wkio_init();

	io_debounce_attr.step_ms = 0;
	io_debounce_attr.detect_fn = gkt_door_tamper_is_detected;
	io_debounce_attr.complete_fn = door_tamper_debounce_complete;
	retval = gkt_io_debounce_config(GKT_IO_DEBOUNCE_ID(door_tamper),
				&io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_tamper.io_debounce_state = DOOR_TAMPER_IO_DEBOUNCE_READY;
	else
		gkt_error("door_tamper: debounce config failed!\n");

	retval = gkt_gpio_config(DOOR_TAMPER_WKIO_GPIO_PIN,
						GKT_GPIO_F_INPUT, NULL);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper_init: <0> config gpio failed %d\n", retval);
		return retval;
	}
#ifndef GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL
	if (GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode) {
		gkt_gpio_get_pin_level(DOOR_TAMPER_WKIO_GPIO_PIN,
				&s_door_tamper_detect_level);
		s_door_tamper_detect_level ^= 1;
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);
	}
#endif

	attr.polarity = (0 == DOOR_TAMPER_DETECT_LEVEL) ?
		GKT_WKIO_POL_FALL_EDGE : GKT_WKIO_POL_RAISE_EDGE;
	attr.check = gkt_door_tamper_is_detected;
	attr.notify = door_tamper_detect_notify;
	retval = gkt_wkio_set(GKT_CONFIG_DOOR_TAMPER_WKIO_PIN, &attr);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper: wkio set failed %d\n", retval);
		return retval;
	}

	return retval;
}

#endif

